package org.eclipse.iota.rules.simplify;

import org.eclipse.iota.arithmetics.IotaOperationExecutor;
import org.eclipse.iota.model.BinaryOperation;
import org.eclipse.iota.model.Expression;
import org.eclipse.iota.model.MultiOperation;
import org.eclipse.iota.model.UnaryOperation;
import org.eclipse.iota.rewrite.AbstractIotaRule;
import org.eclipse.iota.util.IotaCopyUtil;
import org.eclipse.iota.util.IotaEqualityUtil;
import org.eclipse.iota.util.IotaReplaceUtil;

/**
 * Rule for simplifying an expression.
 * @author Christian Krause
 * @generated NOT
 */
public class SimplifyExpression extends AbstractIotaRule {

	/*
	 * (non-Javadoc)
	 * @see org.eclipse.iota.rewrite.AbstractIotaRule#apply(org.eclipse.iota.model.UnaryOperation, boolean)
	 */
	@Override
	public boolean apply(UnaryOperation operation, boolean change) {
		
		// Copy the operand.
		Expression operand = IotaCopyUtil.copy(operation.getOperand());
		
		// Now apply the operation:
		Expression result = IotaOperationExecutor.apply(operand, null, operation);

		// Replace if changed:
		return replaceIfChanged(operation, result, change);
		
	}

	/*
	 * (non-Javadoc)
	 * @see org.eclipse.iota.rewrite.AbstractIotaRule#apply(org.eclipse.iota.model.BinaryOperation, boolean)
	 */
	@Override
	public boolean apply(BinaryOperation operation, boolean change) {
		
		// Copy LHS and RHS.
		Expression left = IotaCopyUtil.copy(operation.getLeft());
		Expression right = IotaCopyUtil.copy(operation.getRight());
		
		// Now apply the operation:
		Expression result = IotaOperationExecutor.apply(left, right, operation);

		// Replace if changed:
		return replaceIfChanged(operation, result, change);
		
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.eclipse.iota.rewrite.AbstractIotaRule#apply(org.eclipse.iota.model.MultiOperation, boolean)
	 */
	@Override
	public boolean apply(MultiOperation operation, boolean change) {
		
		Expression result;

		// Empty expression?
		if (operation.isEmpty()) {
			
			// Replace with neutral element.
			result = operation.createNeutralElement();
		
		} else {
			
			// Copy and rebuild expression:
			result = IotaCopyUtil.copy(operation.getOperands().get(0));
			for (int i=1; i<operation.getOperands().size(); i++) {
				Expression operand = IotaCopyUtil.copy(operation.getOperands().get(i));
				result = IotaOperationExecutor.apply(result, operand, operation);
			}
		}
		
		// Replace if changed:
		return replaceIfChanged(operation, result, change);
		
	}
	
	/*
	 * Replace an expression if it has changed.
	 */
	private boolean replaceIfChanged(Expression original, Expression result, boolean change) {
		boolean hasChanged = !IotaEqualityUtil.equals(original, result);
		if (hasChanged && change) {
			IotaReplaceUtil.replace(original, result);
		}
		return hasChanged;
	}
	
}
